﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;

namespace SharpML.Api.Extensions
{
    /// <summary>
    /// Extension methods for reflection activities
    /// </summary>
    public static class Reflections
    {
        /// <summary>
        /// Scans for any classes within the specified assembly that implement the 
        /// specified interface and passes them back the as a type array
        /// </summary>
        /// <param name="interfaceType">The interface to find</param>
        /// <param name="assembly">The assembly to examine</param>
        /// <returns>An enumerable type collection</returns>
        public static IEnumerable<Type> Discover( this Assembly assembly, Type interfaceType )
        {   
            // Convert to Type[] and return
            return assembly.GetTypes().Where( type => !type.IsAbstract && type.GetInterfaces().Where( contract => interfaceType.IsAssignableFrom( contract ) ).Any() );
        }

        /// <summary>
        /// Returns the description for an enum item
        /// </summary>
        /// <param name="enumeration"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static string GetDescriptionFromAttribute( this Enum enumeration, string defaultValue = null )
        {
            // Localize
            var members = enumeration.GetType().GetMember( enumeration.ToString() );

            // Chain
            return GetDescriptionFromAttribute( members[0], defaultValue ?? enumeration.ToString() );
        }

        /// <summary>
        /// Returns the description for an enum item
        /// </summary>
        /// <param name="enumeration"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static string GetDescriptionFromAttribute( this ICustomAttributeProvider type, string defaultValue = null )
        {
            // Get attribute
            DescriptionAttribute attribute = type.GetCustomAttributes( typeof( DescriptionAttribute ), false ).Cast<DescriptionAttribute>().SingleOrDefault();

            // Return default if nothing found
            if( attribute == null )
                return defaultValue;

            // Otherwise return the description
            return attribute.Description;
        }

        /// <summary>
        /// Checks for an attribute (without walking inheritance chain)
        /// </summary>
        /// <param name="type"></param>
        /// <param name="attributeType"></param>
        /// <returns></returns>
        public static bool HasAnnotation( this ICustomAttributeProvider type, Type attributeType )
        {
            // Return existence of requested attribute
            return type.GetCustomAttributes( attributeType, false ).Any();

        }
    }
}
